#include "serverwindow.h"
#include "ui_serverwindow.h"
#include <QMessageBox>
#include <QImage>
#include <QPixmap>
#include <vector>
#include <opencv2/imgproc.hpp>

ServerWindow::ServerWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::ServerWindow)
{
    ui->setupUi(this);
    server = new QTcpServer(this);

    ui->lineEditParameter->setPlaceholderText(tr("Enter parameter (e.g., 3, 5, 7)"));
    connect(ui->btnStartServer, &QPushButton::clicked, this, &ServerWindow::startServer);
    connect(server, &QTcpServer::newConnection, this, &ServerWindow::onNewConnection);
    connect(ui->btnProcessVideo, &QPushButton::clicked, this, &ServerWindow::processVideo);
    connect(ui->btnSendProcessedVideo, &QPushButton::clicked, this, &ServerWindow::toggleSending);

    timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, &ServerWindow::processAndSendVideo);

    startServer();
}

ServerWindow::~ServerWindow() {
    delete ui;
}

void ServerWindow::startServer() {
    if (!server->listen(QHostAddress::Any, 12345)) {
        QMessageBox::critical(this, "Error", "Failed to start server.");
    } else {
        QMessageBox::information(this, "Server", "Server started. Waiting for connections...");
    }
}

void ServerWindow::onNewConnection() {
    clientSocket = server->nextPendingConnection();
    if (clientSocket) {
        connect(clientSocket, &QTcpSocket::readyRead, this, &ServerWindow::readSocket);
        timer->start(30); // Update frame every 30ms
    }
}

void ServerWindow::readSocket() {
    QByteArray data = clientSocket->readAll();
    if (!data.isEmpty()) {
        std::vector<uchar> buffer(data.begin(), data.end());
        receivedFrame = cv::imdecode(buffer, cv::IMREAD_COLOR);
        if (!receivedFrame.empty()) {
            cv::cvtColor(receivedFrame, receivedFrame, cv::COLOR_BGR2RGB); // Convert to RGB for QImage
            QImage qimg(receivedFrame.data, receivedFrame.cols, receivedFrame.rows, receivedFrame.step, QImage::Format_RGB888);
            ui->labelReceivedVideo->setPixmap(QPixmap::fromImage(qimg));
        }
    }
}

void ServerWindow::processVideo() {
    if (!receivedFrame.empty()) {
        bool isValid;
        int param = ui->lineEditParameter->text().toInt(&isValid);

        if (!isValid || param <= 0 || param % 2 == 0) {
            QMessageBox::warning(this, "Invalid Input", "Parameter must be a positive odd number (e.g., 3, 5, 7).");
            return;
        }

        // Simple Skin Smoothing Algorithm (磨皮算法)
        cv::Mat blurredFrame;
        cv::GaussianBlur(receivedFrame, blurredFrame, cv::Size(param, param), 0);

        // Blend original and blurred frames
        cv::addWeighted(receivedFrame, 0.5, blurredFrame, 0.5, 0, processedFrame);

        cv::cvtColor(processedFrame, processedFrame, cv::COLOR_RGB2BGR); // Convert to BGR for display
        QImage qimg(processedFrame.data, processedFrame.cols, processedFrame.rows, processedFrame.step, QImage::Format_RGB888);
        ui->labelProcessedVideo->setPixmap(QPixmap::fromImage(qimg));
    }
}

void ServerWindow::toggleSending() {
    isSending = !isSending; // Toggle the sending state
    if (isSending) {
        QMessageBox::information(this, "Sending", "Sending processed video...");
        timer->start(30); // Start sending frames
    } else {
        QMessageBox::information(this, "Stopped", "Stopped sending video.");
        timer->stop(); // Stop sending frames
    }
}

void ServerWindow::processAndSendVideo() {
    if (!receivedFrame.empty()) {
        processVideo(); // Process the frame

        // Send the processed frame
        cv::cvtColor(processedFrame, processedFrame, cv::COLOR_BGR2RGB); // Convert back to RGB for encoding
        std::vector<uchar> buffer;
        cv::imencode(".jpg", processedFrame, buffer, {cv::IMWRITE_JPEG_QUALITY, 95});
        QByteArray data(reinterpret_cast<const char*>(buffer.data()), buffer.size());
        clientSocket->write(data);
        clientSocket->flush();
    }
}
